﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ObjectComposition
{
    public class Command
    {
        public Func<bool> Enabled = () => true;
        public Action Action;
        protected List<CommandBinding> bindings = new List<CommandBinding>();
        public void AddBinding(CommandBinding binding)
        {
            this.bindings.Add(binding);
        }

        public virtual void Execute()
        {
            if (this.Enabled())
            {
                foreach (CommandBinding binding in this.bindings)
                    binding.Execute();
                if (this.Action != null)
                    this.Action();
            }
        }

        public virtual void Execute(object parameter1)
        {
            throw new Exception("Incorrect number of command parameters.");
        }

        public virtual void Execute(object parameter1, object parameter2)
        {
            throw new Exception("Incorrect number of command parameters.");
        }

        public virtual void Execute(object parameter1, object parameter2, object parameter3)
        {
            throw new Exception("Incorrect number of command parameters.");
        }

        protected void validateType(object parameter, Type type)
        {
            if ((parameter == null && type.IsValueType) || (parameter != null && !parameter.GetType().IsAssignableFrom(type)))
                throw new Exception("Incorrect parameter type. Expected \"" + type.Name + "\", got \"" + parameter.GetType().Name + "\".");
        }
    }

    public class Command<Type> : Command
    {
        public new Action<Type> Action;
        public override void Execute()
        {
            throw new Exception("Incorrect number of command parameters.");
        }
        public override void Execute(object parameter)
        {
            if (this.Enabled())
            {
#if DEBUG
                this.validateType(parameter, typeof(Type));
#endif
                foreach (CommandBinding binding in this.bindings)
                    binding.Execute(parameter);
                if (this.Action != null)
                    this.Action((Type)parameter);
            }
        }
    }

    public class Command<Type, Type2> : Command
    {
        public new Action<Type, Type2> Action;
        public override void Execute()
        {
            throw new Exception("Incorrect number of command parameters.");
        }
        public override void Execute(object parameter1, object parameter2)
        {
            if (this.Enabled())
            {
#if DEBUG
                this.validateType(parameter1, typeof(Type));
                this.validateType(parameter2, typeof(Type2));
#endif
                foreach (CommandBinding binding in this.bindings)
                    binding.Execute(parameter1, parameter2);
                if (this.Action != null)
                    this.Action((Type)parameter1, (Type2)parameter2);
            }
        }
    }

    public class Command<Type, Type2, Type3> : Command
    {
        public new Action<Type, Type2, Type3> Action;
        public override void Execute()
        {
            throw new Exception("Incorrect number of command parameters.");
        }
        public override void Execute(object parameter1, object parameter2, object parameter3)
        {
            if (this.Enabled())
            {
#if DEBUG
                this.validateType(parameter1, typeof(Type));
                this.validateType(parameter2, typeof(Type2));
                this.validateType(parameter3, typeof(Type3));
#endif
                foreach (CommandBinding binding in this.bindings)
                    binding.Execute(parameter1, parameter2, parameter3);
                if (this.Action != null)
                    this.Action((Type)parameter1, (Type2)parameter2, (Type3)parameter3);
            }
        }
    }
}
